package com.ymx.darling.expression;

import com.ymx.darling.exception.ExpressionException;
import com.ymx.darling.util.ArrayUtil;
import com.ymx.darling.util.StringUtil;

import java.util.*;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 根据表达式构建Token
 * @author 爱Java的小于
 */
public class TokenParser {
    // 定义可能的运算符起始字符
    private static final Set<Character> CHAR_CODE = new HashSet<>(ArrayUtil.asList('>', '=', '!'));
    private static final Set<String> STRING_CODE = new HashSet<>(ArrayUtil.asList("and", "or", "lt", "le"));
    // Token缓存，用于存储已经解析过的表达式
    private static final Map<String, List<Token>> tokenCache = new ConcurrentHashMap<>();
    // 空格字符
    private static final char SPACE = ' ';
    // 单引号字符
    private static final char SINGLE_QUOTE = '\'';

    /**
     * 解析表达式为一个Token列表。第一次解析的列表会放入缓存。
     * @param expression 字符串表达式
     * @return Token列表
     */
    public List<Token> parse(String expression) {
        // 使用缓存避免重复解析相同的表达式
        return tokenCache.computeIfAbsent(expression, this::doParse);
    }


    /**
     * 开始解析Token
     * @param expression 字符串表达式
     * @return Token列表
     */
    private List<Token> doParse(String expression) {
        List<Token> tokens = new ArrayList<>();

        if (StringUtil.isNoNull(expression)) {
            StringBuilder itemBuilder = new StringBuilder(); // 用于构建当前项
            char c;

            for (int i = 0, len = expression.length(); i < len; i++) {
                c = expression.charAt(i);
                // 处理单引号字符
                if (c == SINGLE_QUOTE) {
                    this.appendTokenToList(itemBuilder.toString(), tokens);
                    StringBuilder charBuilder = new StringBuilder();
                    charBuilder.append(SINGLE_QUOTE);
                    for (int j = i + 1; j < len; j++) {
                        c = expression.charAt(j);
                        charBuilder.append(c);
                        if (c == SINGLE_QUOTE) {
                            i = j;
                            break;
                        }
                    }
                    // 当单引号未闭合时抛出异常
                    if (c != SINGLE_QUOTE) {
                        throw new ExpressionException("索引位置为"+i+"的单引号未闭合");
                    }
                    this.appendTokenToList(charBuilder.toString(), tokens);
                    itemBuilder = new StringBuilder();
                }
                // 处理空格
                else if (c == SPACE) {
                    this.appendTokenToList(itemBuilder.toString(), tokens);
                    itemBuilder = new StringBuilder();
                }
                // 处理括号
                else if (c == '(' || c == ')') {
                    // 判断无效括号()直接跳过
                    if (c == '(' && i < len - 1 && expression.charAt(i+1) == ')') {
                        i++;
                    } else {
                        this.appendTokenToList(itemBuilder.toString(), tokens);
                        itemBuilder = new StringBuilder();
                        this.appendTokenToList(String.valueOf(c), tokens);
                    }
                }
                // 处理运算符
                else if (CHAR_CODE.contains(c)) {
                    this.appendTokenToList(itemBuilder.toString(), tokens);
                    itemBuilder = new StringBuilder();
                    StringBuilder codeBuilder = new StringBuilder();
                    codeBuilder.append(c);

                    // 处理多字符运算符（如 >=, <=, ==, !=）
                    int nextIndex = i + 1;
                    if (nextIndex < len && CHAR_CODE.contains(expression.charAt(nextIndex))) {
                        codeBuilder.append(expression.charAt(nextIndex));
                        i++;
                    }
                    this.appendTokenToList(codeBuilder.toString(), tokens);
                }
                // 处理数字、变量名、字符串等
                else {
                    itemBuilder.append(c);
                }
            }

            // 处理最后一个未处理的项
            this.appendTokenToList(itemBuilder.toString(), tokens);
        }
        return tokens;
    }


    /**
     * 构建并添加Token到列表中
     * @param item 字符串项
     * @param tokens Token列表
     */
    private void appendTokenToList(String item, List<Token> tokens) {
        if (StringUtil.isNoNull(item)) {
            // 判断是否是比较运算符
            if (CHAR_CODE.contains(item.charAt(0)) || STRING_CODE.contains(item)) {
                tokens.add(new Token(TokenType.OPERATOR, item));
            }
            // 判断是否是括号
            else if (item.equals("(") || item.equals(")")) {
                tokens.add(new Token(TokenType.BRACKET, item));
            }
            // 判断是否是null
            else if ("null".equals(item)) {
                tokens.add(new Token(TokenType.NULL, item));
            }
            // 判断是否是数字
            else if (item.matches("-?\\d+(\\.\\d+)?")) {
                tokens.add(new Token(TokenType.NUMBER, item));
            }
            // 判断是否是布尔值
            else if (item.equals("false") || item.equals("true")) {
                tokens.add(new Token(TokenType.BOOLEAN, item));
            }
            // 判断是否是字符串（单引号包裹）
            else if (item.startsWith("'") && item.endsWith("'")) {
                tokens.add(new Token(TokenType.STRING, item));
            }
            // 剩下的视为变量名或表达式
            else {
                tokens.add(new Token(TokenType.ACCESS_EXPRESSION, item));
            }
        }
    }
}